package opencv.service.servers;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

/**
 * @author Aakash Polra
 */
public class TCPServer  implements Runnable {

	public final static int DEFAULT_PORT = 9001;
	
	private int port;
	private Socket socket;
	private ServerSocket server;
	
	public TCPServer(int port) {
		this.port = port;
	}
	
	/**
	 * starts the tcp server
	 */
	public void start() {
		new Thread(this).start();
	}
	
	/**
	 * A handy utility method which uses this{@link #send(byte[])} and {@link TCPServer#bytesValue(int)}
	 * to send 4 integers to any connected client
	 */
	public void send(int x, int y, int w, int h) {
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			bos.write(bytesValue(x));
			bos.write(bytesValue(y));
			bos.write(bytesValue(w));
			bos.write(bytesValue(h));

			send(bos.toByteArray());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Sends given data to any connected client
	 * It doesn't do anything if no clients are connected
	 * 
	 * @param data bytes to send to a connected client
	 */
	public void send(byte[] data) {
		if (socket != null) {
			try {
				socket.getOutputStream().write(data);
				socket.getOutputStream().flush();
			} catch (SocketException se) {
				try { socket.close(); } catch (Exception e) { }
				socket = null;
				stop();
				start();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			// no clients are connected
		}
	}
	
	/**
	 * Gives 4 bytes for given integer
	 * 
	 * @param i integer value you want to convert
	 * @return 4 bytes representing given integer
	 */
	public static byte[] bytesValue(int i) {
		byte[] bytes = new byte[4];
		int hexBase = 0xff;
		bytes[0] = (byte)(hexBase & i);
		bytes[1] = (byte)(((hexBase << 8) & i) >> 8);
		bytes[2] = (byte)(((hexBase << 16) & i) >> 16);
		bytes[3] = (byte)(((hexBase << 24) & i) >> 24);
		
		return bytes;
	}
	
	/**
	 * Stops the tcp server if it was ever started
	 */
	public void stop() {
		if (server != null) {
			try {
				server.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Starts a tcp server and accepts one incoming connection
	 */
	@Override
	public void run() {
		
		System.out.println("starting tcp server on port " + port + "...");
		try {
			server = new ServerSocket(port);
			socket = server.accept();
			System.out.println("connection made.");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}